package logic

import (
	"core/command"
	"core/common"
	"core/component/logger"
	"core/logic/logicredis"
	"fmt"
	"sync"
)

var (
	world *World
)

type World struct {
	players           *sync.Map
	stop              chan int
	chanPlayerOffline chan uint64
	chanPlayerOnline  chan *PlayerData
	removePlayerChan  chan uint64
}

func (w *World) Init() {
	world = &World{
		players:           &sync.Map{},
		stop:              make(chan int, 1),
		chanPlayerOffline: make(chan uint64, 128*1024),
		chanPlayerOnline:  make(chan *PlayerData, 128*1024),
		removePlayerChan:  make(chan uint64, 128*1024),
	}
	go world.loop()
	logger.Info("world Init Success")
}

func WorldGetMe() *World {
	return world
}

func (w *World) loop() {
	for {
		select {
		case info := <-w.chanPlayerOnline:
			w.doLoginPlayer(info)
		case id := <-w.chanPlayerOffline:
			w.dealPlayerOffline(id)
		case id := <-w.removePlayerChan:
			w.removePlayer(id)
		case <-world.stop:
			return
		}
	}
}

func (world *World) doLoginPlayer(info *PlayerData) {
	player := WorldGetMe().addPlayer(info.playerId, info.gatewayIp, info.gatewaySrvID)
	if player == nil {
		return
	}
	player.isGotoPvpServer = true
	player.playerIntoPvp()
	msgSend := &command.SCPlayerLoginInfo{}
	msgSend.PlayerId = player.playerId
	msgSend.Ret = command.NoticeType_Success
	msgSend.IsNewPlayer = info.isNew
	msgSend.NickName = player.user.nickName
	msgSend.IsVisitor = info.isVisitor
	player.sendMsg(command.Command_SCPlayerLoginInfo_Gateway, msgSend)
	logicredis.CacheRedis().Set(common.MakePlayerIsOnline(player.playerId), 1, 0)
}

func (world *World) sendRemovePlayer(id uint64) {
	world.removePlayerChan <- id
}

func (world *World) sendLoginPlayerChan(info *PlayerData) {
	world.chanPlayerOnline <- info
}

func (world *World) dealPlayerOffline(playerId uint64) {
	player := WorldGetMe().getPlayer(playerId)
	if player == nil {
		return
	}
	msgSend := &command.SCPlayerLogoutRet{}
	msgSend.Ret = true
	player.sendMsg(command.Command_SCPlayerLogoutRet_Gateway, msgSend)
	player.handleOfflineOP(0)
}

func (w *World) getPlayer(playerId uint64) *Player {
	player, ok := w.players.Load(playerId)
	if !ok {
		return nil
	}
	return player.(*Player)
}

func (w *World) addPlayer(playerId uint64, clientAddr, gatewaySrvID string) *Player {
	if _, ok := w.players.Load(playerId); ok {
		return nil
	}
	player := newPlayer(playerId, clientAddr, gatewaySrvID)
	logger.Infof("玩家(%v)进入 online", playerId)
	w.players.Store(playerId, player)
	logger.Infof("添加玩家(%v) onlineWorld", playerId)
	return player
}

func (w *World) removePlayer(playerId uint64) {
	p, ok := world.players.Load(playerId)
	if !ok {
		return
	}

	player, ok := p.(*Player)

	if !ok {
		return
	}

	world.players.Delete(player.playerId)

	player = nil
	logger.Infof("移除玩家(%v) onlineWorld", playerId)
}

func (w *World) clientInOnline(playerId uint64, gatewayAddr, remoteAddr, gatewaySrvID string, isNew bool, isVisitor bool) {
	info := &PlayerData{
		playerId:     playerId,
		gatewayIp:    gatewayAddr,
		gatewaySrvID: gatewaySrvID,
		isNew:        isNew,
		isVisitor:    isVisitor,
		remoteAddr:   remoteAddr,
	}
	w.sendLoginPlayerChan(info)
}

func (w *World) clientOutOnline(playerId uint64) {
	w.chanPlayerOffline <- playerId
}

func (world *World) FinializeSave() {
	world.players.Range(func(k, v interface{}) bool {
		player, ok := v.(*Player)
		if ok && !player.isOffline {
			player.handleOfflineOP(0)
		}
		return true
	})
	world.stop <- 1
}

func (world *World) handlePlayersMsgPacket(playerID uint64, data []byte) error {
	player := world.getPlayer(playerID)
	if player != nil {
		msgData := &common.PlayerMsgData{PlayerID: playerID}
		msgData.Data = make([]byte, len(data))
		copy(msgData.Data, data)
		player.handleClientMsgPacket(msgData)
		return nil
	}
	return fmt.Errorf("[msg] 玩家消息处理错误")
}
